#include <kernel/bus.h>
#include <kernel/initcall.h>
#include <kernel/syslog.h>
#include <drivers/platform.h>
#include <lib/eb_string.h>


static int platform_bus_match(struct device *dev, struct driver *drv)
{
    int ret = -1;
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    if(pdrv->id_table) {
        ret = bus_attach_match_id(pdrv->id_table, dev->name);

        if(ret < 0) {
            ret = bus_attach_match_id(pdrv->id_table, pdev->compatible);
        }
    }

    if(ret < 0) {
        if (bus_attach_match_name(dev->name, drv->name) == 0) {
            SYSLOG_INFO("%s bus: match successful: name = %s", drv->bus->name, drv->name);
            return 0;
        }
    }
    else {
        pdev->platform_data = pdrv->id_table[ret].data;
        SYSLOG_INFO("%s bus: match successful: match table = [%d], %s", drv->bus->name, ret, pdrv->id_table[ret].compatible);
        return 0;
    }

    SYSLOG_INFO("%s bus: no matching driver available for %s", drv->bus->name, dev->name);
    return -1;
}


static int platform_bus_probe(struct device *dev)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(dev->driver);

    if(pdrv && pdrv->probe) {
        return pdrv->probe(pdev);
    }

    return 0;
}


static void platform_bus_remove(struct device *dev)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(dev->driver);

    if(pdrv->remove) {
        pdrv->remove(pdev);
    }
}


struct bus_type platform_bus = {
    .name = "platform",
    .match = platform_bus_match,
    .probe = platform_bus_probe,
    .remove = platform_bus_remove,
};


static int platform_bus_register(void)
{
    return bus_register(&platform_bus);
}


bus_initcall(platform_bus_register);
